DockerとAWSのコラボによりdocker ecsコマンドが爆誕したので使ってみた
「docker ecsコマンド?なにこれ?」
先日、突如、DockerのECSインテグレーションなるものが発表されました!
AWS and Docker collaborate to simplify the developer experience | Containers
従来あるdockerコマンドに、なんとdocker ecs
コマンドが追加され、docker-composeファイルを利用したECSへのデプロイがAWS CLIなどのAWS製ツールを使わずに、全てdockerコマンドだけで完結するという、ちょっと想像がつかないアップデートです。
まだDocker社ではベータ版の扱いということですが、なかなかにおもしろいアプローチだったので、基本的な操作を一通り確認してみた様子をお届けします。
(祭) ∧ ∧ Y ( ゚Д゚) Φ[_ソ__y_l〉 dockerとecsマツリダワッショイ |_|_| し'´J
dockerとAWSのインテグレーションとは
概要は、dockerの公式ブログを参照。
From Docker Straight to AWS - Docker Blog
複数のコンテナを協調動作させつつデプロイし、環境をセットアップするための、docker composeは広く使われています。今回のDocker社とAWSとのパートナーシップにより、dockerに、docker ecs
コマンドが追加され、ECSやFargateに統合さることになりました。7月20日時点では、ベータ版での提供となります。
動画はこちら。たった30秒ほどの動画ですが、何ができるのか直感的にわかるので、最初に見ていただくことをオススメします。
dockerのECS Integrationを動かしてみる!
正直、話を聞いていてもなかなかイメージが沸かないので(自分も)、Docker社でホストされているGitHubを参考に実際に動かしてみた様子をお届けします。基本的な流れは、すべてGitHubにアップされているものを利用しています。ただ、一部情報を補完するために、Dockerの公式ドキュメントも合わせて参照しています。
- Github
- Docker Document
手順は以下の通り。
- Docker Desktop Edgeのインストール
- プライベートDocker Hubリポジトリアクセスのためのクレデンシャル格納
- docker contestの用意
- サンプルアプリケーションのローカル動作確認
- ECSで利用するイメージをDockerHubにプッシュ
- ECSへのデプロイ
- デプロイされたECSの構造を理解する
- docker ecs compose関連コマンド
- デプロイリソースの削除
Docker Desktop Edgeのインストール
前提として、Docker Desktop Edgeが必要。EdgeはStableの安定版とは違うため、通常の利用ではインストールしている人は少ないと思います。自分の環境はmacOSなので、公式ページの「Get Edge」ボタンより、ダウンロードしてインストールしておきます。
Docker Desktop for Mac - Docker Hub
Edge版インストールするときは、「クライアントのコンテナやイメージをバッサリ削除するで!」と注意書きがでます。docker使って現在バリバリ開発中の方は、もしかしたら痛い目にあうかもなので、ある程度覚悟してインストールしましょう。
インストールして起動すると、Channel部分にedgeと表示されます。
インストール完了したら、次にいってみましょ!
プライベートDocker Hubリポジトリアクセスのためのアクセストークンを作成
事前に自身のDockrHubアカウントにアクセストークンをセットアップする必要があります。まだアクセストークンを取得していない場合は、こちら(Managing access tokens | Docker Documentation)を参考にトークンを作成しておきます。
docker contextの用意
dockerコマンドを利用してAWSに接続するためのContextをセットアップします。コマンドはdocker ecs setup
で、これを入力し、awsにアクセスするprofile名とregion内容を設定します。すでにAWS CLIなどでAWSに接続できる状態になっていれば、AWS Profileを選択することで設定が完了します。
下の例では、Profileにdocker-ecs-user
を選択。既存Profileを選択するのであれば、別途Credentialsの入力は不要です。
$ docker ecs setup Enter context name: aws█ ✔ docker-ecs-user ? Enter region: ap-northeast-1 ? Enter credentials? [y/N] N█
すべて正常に完了したら、docker context ls
コマンドで、Docker contextsが正常にセットアップされているか確認。NAME
に、aws
が表示されていればOK。
$ docker context ls NAME TYPE DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR aws aws default * moby Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm
docker ecs setup時のエラーについて
自分の環境では、docker ecs setup
実行時、以下のエラーがでてました。
this tool requires the "new ARN resource ID format"
こちら、GitHubにissueが上がってます。
エラー解決方法は、ECSのアカウント設定でサービス名の新しいARN形式のオプトインが必要になります。設定手順のマニュアルはこちら。
確認方法を簡単に紹介。以下のコマンドでECSの各リソースのオプトイン状況が確認できます。value
がdisabled
になっている値は、オプトインされていません。
$ aws ecs list-account-settings --effective-settings { "settings": [ { "name": "awsvpcTrunking", "value": "disabled", "principalArn": "arn:aws:iam::123456789012:user/docker-ecs-user" }, { "name": "containerInsights", "value": "disabled", "principalArn": "arn:aws:iam::123456789012:user/docker-ecs-user" }, { "name": "containerInstanceLongArnFormat", "value": "disabled", "principalArn": "arn:aws:iam::123456789012:user/docker-ecs-user" }, { "name": "serviceLongArnFormat", "value": "disabled", "principalArn": "arn:aws:iam::123456789012:root" }, { "name": "taskLongArnFormat", "value": "disabled", "principalArn": "arn:aws:iam::123456789012:user/docker-ecs-user" } ] }
この際だから全てオプトインする場合は、それぞれのサービスに対して、オプトインを実施していきます。
aws ecs put-account-setting-default --name awsvpcTrunking --value enabled aws ecs put-account-setting-default --name containerInsights --value enabled aws ecs put-account-setting-default --name containerInstanceLongArnFormat --value enabled aws ecs put-account-setting-default --name serviceLongArnFormat --value enabled aws ecs put-account-setting-default --name taskLongArnFormat --value enabled
再度設定確認し、それぞれのvalue
がenabled
になっていることを確認しましょう。設定が終わったら、再度docker ecs setup
を実行してみてください。
このエラー解消方法については、tori様の声が天から降ってきたことをご報告しておきます。いつもありがとうございます!
ECS の long ARN format 有効にしてみるとどうですか?
— ポジティブな Tori (@toricls) July 22, 2020
サンプルアプリケーションのローカル動作確認
サンプルアプリケーションをローカルで動作確認します。
$ git clone https://github.com/docker/ecs-plugin.git $ cd ecs-plugin/example/
docker context
をdefault
に切替。
$ docker context use default default
サンプルアプリケーションをローカルで起動し、画面が起動することを確認。
docker-compose up
ブラウザでhttp://localhost:5000/
にアクセスし、下記のような画面が表示されたらOK。
ECSで利用するイメージをDocker Hubにプッシュ
前提として、dockerコマンドを利用したECSのデプロイで使うイメージはDocker Hubの自分のアカウントにアップロードします。通常、ECSでは利用イメージをECRに置くことが多いですが、この場合はECRではないことにご注意ください。
プッシュ前に、docker-compose.yml
の以下の部分を書き換えます。
image: <<<your docker hub user name>>>/timestamper
プッシュ先のイメージのURIを指定するため、自分のDockr HubアカウントIDを埋めます。自分の場合は、こんな感じ。
image: hamako9999/timestamper
自分のDocker Hubアカウントに、前手順で作成したパーソナルアクセストークンを利用して、ログインします。
$ docker login --username hamako9999 Password: Login Succeeded
ログイン成功したら、docker-compose push
コマンドでイメージをプッシュします。
$ docker-compose push Pushing frontend (hamako9999/timestamper:latest)... The push refers to repository [docker.io/hamako9999/timestamper] c94062adef57: Pushed dce45b6ec708: Pushed 8209fa3a4eda: Pushed f7edcfe22288: Pushed 5afde73d5bad: Pushed b10be96d1b4e: Layer already exists 003d0b48eda4: Pushed 408e53c5e3b2: Pushed 50644c29ef5a: Pushed latest: digest: sha256:07066276826c22d9bbbbae05dc21eb48b39c0a5d9b45410bcb2cda8d565ea438 size: 2201
自身のDocker Hubアカウントにアクセスしてみてください。このようにtimestamper
イメージがプッシュされていればOKです。
ECSへのデプロイ
ECSタスクの起動時にDocker Hubアクセスしてイメージを取得するため、アクセストークンをAWS環境上にセットアップしておく必要があります。このための便利コマンドが用意されていて、AWS CLIを使わずにdockerコマンドを利用して、AWS上にアクセストークンを格納できます。
$ docker ecs secret create dockerhubAccessToken --username hamako9999 --password <dockerhubtoken> arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:dockerhubAccessToken-qftyOp
AWSのSecrets Managerにアクセスすると、シークレットが格納されていることが確認できます。
この作成されたトークンのARNをdocker-compose.yml
のx-aws-pull_credentials
に記入します。
x-aws-pull_credentials: <<<your arn for your secret you can get with docker ecs secret list>>>
これで、ECSアップロードのための準備は完了ですよ!
コンテキストをAWSに切り替えてアプリケーションの起動
前手順で作成したAWSアクセス用のContextに切り替えます。
docker context use aws
いよいよ、AWSにアプリケーションをデプロイします。コマンドは単純至極。作られるリソースにLoadBalancerなどもあるため、作成完了まで5分程度必要になります。
docker ecs compose up
無事すべての処理が正常に完了したでしょうか?まだベータ版のため、ちょくちょくエラーが発生すると思いますが頑張ってください。自分の場合は、一度Secrets ManagerのARNが誤っていて、修正後再デプロイしようとすると、CloudMapで作成したホストゾーンが名前重複して再作成できませんでした。
このあたりは、ECSと周辺サービスの構造をある程度理解していないと対処が難しいと思うので、それなりの覚悟が必要です。
デプロイされたECSの構造を理解する
上記コマンドで、docker-compose.ymlに記載されている内容をAWSに展開するためにCloudFormationが展開され各種AWSリソースがガッツリ作成されます。CloudFormationのコンソールには、app
スタックが作成されており、含まれているAWSリソースはこのあたり。
- LogGroup
- FrontendTaskExecutionRole
- FrontendTaskDefinition
- FrontendTCP5000TargetGroup
- FrontendTCP5000Listener
- FrontendServiceDiscoveryEntry
- FrontendService
- Cluster
- CloudMap
- BackendTaskExecutionRole
- BackendTaskDefinition
- BackendServiceDiscoveryEntry
- BackendService
- AppLoadBalancer
- AppDefaultNetworkIngress
- AppdefaultNetwork
構成図で表すとこうなります。
VPCはdefault-VPCが利用され、ECSクラスターは新規で作成されます。FrontEndコンテナとBackendコンテナがそれぞれFargateで起動します。EC2は作成されません。
LoadBalancerがNLBで作成され、外部通信はdocker-composeファイルに記載の通り、ポート5000で受け、ポート5000で受けるリスナーが作成され、ターゲットグループにFrontEndのECSタスクが登録されます。このポート5000を受けるためのセキュリティグループも自動的に設定されます。
FrontEndコンテナとBackendコンテナの通信はサービスディカバリー経由となるため、VPCに紐付いたプライベートゾーンがCloudMap経由で作成され、ECSタスクがCloudMapの各サービスに紐づきます。
FrontendのECSタスク定義は、イメージをDocker Hubの自分のアカウントから取得する用に設定されています。そのときに必要な認証情報のパラメーターは、予め作成しておいたSecretsManagerのアクセストークンを利用するように認証情報パラメーターとして指定されます。この状態ではECRは作成されていません。
ECS関連コンポーネントについて説明しました。イメージ湧きますでしょうか?FrontendコンテナとBackendコンテナ間の通信をCloudMapによるサービスディスカバリーで実現しているのは、インターナルなロードバランサーを使うよりコストでも構築スピードでもメリットがあって良いですね。
実際にデプロイされたコンテナの動作確認には、作成されたNLBのエンドポイントにポート5000でアクセスしてみてください。
docker ecs compose関連コマンドを理解する
docker ecs compose コマンドには他にもいくつかコマンドがあります。
$ docker ecs compose --help Usage: docker ecs compose [OPTIONS] COMMAND Options: -f, --file stringArray Specify an alternate compose file -n, --project-name string Specify an alternate project name (default: directory name) Commands: convert down logs ps up
docker ecs compose ps
で、起動しているコンテナの状態を確認できます。
$ docker ecs compose ps ID NAME REPLICAS PORTS example-BackendService-LKYCYBC7UQS9 backend 1/1 example-FrontendService-LKMZSMS7EENO frontend 1/1
docker ecs compose convert
で、AWSリソースの作成に利用されたCloudFormationテンプレートを出力できます。JSONなのが辛いですが。
docker ecs compose logs
で、コンテナ内ログをtail状態でターミナルに出力できます。
$ docker ecs compose logs backend | 1:C 23 Jul 2020 01:57:56.971 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo backend | 1:C 23 Jul 2020 01:57:56.971 # Redis version=6.0.6, bits=64, commit=00000000, modified=0, pid=1, just started backend | 1:C 23 Jul 2020 01:57:56.971 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf backend | 1:M 23 Jul 2020 01:57:56.973 # You requested maxclients of 10000 requiring at least 10032 max file descriptors. backend | 1:M 23 Jul 2020 01:57:56.973 # Server can't set maximum open files to 10032 because of OS error: Operation not permitted. backend | 1:M 23 Jul 2020 01:57:56.973 # Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'. backend | 1:M 23 Jul 2020 01:57:56.974 * Running mode=standalone, port=6379. backend | 1:M 23 Jul 2020 01:57:56.974 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. backend | 1:M 23 Jul 2020 01:57:56.974 # Server initialized backend | 1:M 23 Jul 2020 01:57:56.974 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect. backend | 1:M 23 Jul 2020 01:57:56.974 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled. backend | 1:M 23 Jul 2020 01:57:56.974 * Ready to accept connections frontend | * Serving Flask app "app" (lazy loading) frontend | * Environment: production frontend | WARNING: This is a development server. Do not use it in a production deployment. frontend | Use a production WSGI server instead. frontend | * Debug mode: on frontend | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) frontend | * Restarting with stat frontend | * Debugger is active! frontend | * Debugger PIN: 206-344-428
デプロイリソースの削除
ここは、docker-composeのお作法と同じですね。docker ecs compose down
で、作成されたリソースはすべて削除されます。
docker ecs compose down
このコマンドでどうしても削除できない場合は、マネジメントコンソールからCloudFormationを開いて、関連リソースを順次削除していきましょう。
docker-composeを利用している環境を、ECS上で動作確認をするのに非常に便利
以上、長くなりましたが、docker-composeを利用したECSインテグレーションについて説明してきました。データベースをコンテナで動かしている場合でも、Fargateのストレージサイズで足りる容量であれば、すんなりECSにデプロイできるかと思います。
基本的には、既存のdocker-composeファイルにDocker Hubアクセス用のトークンが格納されたSecrets ManagerのARNを挿入するだけで、ECSデプロイされるのは革命的に便利なのではないでしょうか。また、別オプションを使えば、既存のECSクラスターやVPCやロードバランサーを利用してデプロイできたり、イメージをECRから取得するように変更可能です。
そのあたりの追加のコマンドや、プラグインについては、Dockerの公式ドキュメントに記載されているので、合わせて確認してみてください。
参考:Tuning the CloudFormation template | Docker Documentation
それでは、今日はこのへんで。濱田(@hamako9999)でした。